Modelo

source("../../lib/som-utils.R")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
source("../../lib/maps-utils.R")
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

Carga del modelo desde disco

mpr.set_base_path_analysis()
model <- mpr.load_model("som-329.rds.xz")
summary(model)
SOM of size 5x5 with a hexagonal topology and a bubble neighbourhood function.
The number of data layers is 1.
Distance measure(s) used: sumofsquares.
Training data included: 94881 objects.
Mean distance to the closest unit in the map: 0.415.
plot(model, type="changes")

Carga del dataset de entrada

df <- mpr.load_data("datos_mes.csv.xz")
df
summary(df)
 id_estacion           fecha             fecha_cnt           tmax      
 Length:94881       Length:94881       Min.   : 1.000   Min.   :-53.0  
 Class :character   Class :character   1st Qu.: 4.000   1st Qu.:148.0  
 Mode  :character   Mode  :character   Median : 6.000   Median :198.0  
                                       Mean   : 6.497   Mean   :200.2  
                                       3rd Qu.: 9.000   3rd Qu.:255.0  
                                       Max.   :12.000   Max.   :403.0  
      tmin             precip           nevada           prof_nieve      
 Min.   :-121.00   Min.   :  0.00   Min.   :0.000000   Min.   :   0.000  
 1st Qu.:  53.00   1st Qu.:  3.00   1st Qu.:0.000000   1st Qu.:   0.000  
 Median :  98.00   Median : 10.00   Median :0.000000   Median :   0.000  
 Mean   :  98.86   Mean   : 16.25   Mean   :0.000295   Mean   :   0.467  
 3rd Qu.: 148.00   3rd Qu.: 22.00   3rd Qu.:0.000000   3rd Qu.:   0.000  
 Max.   : 254.00   Max.   :422.00   Max.   :6.000000   Max.   :1834.000  
    longitud        latitud            altitud      
 Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:38.28   1st Qu.: -5.6417   1st Qu.:  42.0  
 Median :40.82   Median : -3.4500   Median : 247.0  
 Mean   :39.66   Mean   : -3.4350   Mean   : 418.5  
 3rd Qu.:42.08   3rd Qu.:  0.4914   3rd Qu.: 656.0  
 Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

Carga de los mapas

world <- ne_countries(scale = "medium", returnclass = "sf")
spain <- subset(world, admin == "Spain")

Mapa de densidad

plot(model, type="count", shape = "straight", palette.name = mpr.degrade.bleu)

NĂºmero de elementos en cada celda:

nb <- table(model$unit.classif)
print(nb)

   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16 
  96  637 1422 2482 3730 1010  607 1605 3504 5136 4703 2206 4637 4035 5280 4599 
  17   18   19   20   21   22   23   24   25 
7511 6468 5697 4686 6281 2224 4715 6215 5395 

ComprobaciĂ³n de nodos vacĂ­os:

dim_model <- 5*5;
len_nb = length(nb);
empty_nodes <- dim_model != len_nb;
if (empty_nodes) {
  print(paste("[Warning] Existen nodos vacĂ­os: ", len_nb, "/", dim_model))
}

Mapa de distancia entre vecinos

plot(model, type="dist.neighbours", shape = "straight")

Influencia de las variables

model_colnames = c("fecha_cnt", "tmax", "tmin", "precip")
model_ncol = length(model_colnames)

Mapa de variables.

plot(model, shape = "straight")

Mapa de calor por variable

par(mfrow=c(3,4))
for (j in 1:model_ncol) {
  plot(model, type="property", property=getCodes(model,1)[,j],
    palette.name=mpr.coolBlueHotRed,
    main=model_colnames[j],
    cex=0.5, shape = "straight")
}

CorrelaciĂ³n para cada columna del vector de nodos

if (!empty_nodes) {
  cor <- apply(getCodes(model,1), 2, mpr.weighted.correlation, w=nb, som=model)
  print(cor)
}
      fecha_cnt      tmax      tmin     precip
[1,]  0.8690262 0.5110964 0.5481421 -0.2123885
[2,] -0.5325620 0.5550952 0.4975107 -0.5807435

RepresentaciĂ³n de cada variable en un mapa de factores:

if (!empty_nodes) {
  par(mfrow=c(1,1))
  plot(cor[1,], cor[2,], xlim=c(-1,1), ylim=c(-1,1), type="n")
  lines(c(-1,1),c(0,0))
  lines(c(0,0),c(-1,1))
  text(cor[1,], cor[2,], labels=model_colnames, cex=0.75)
  symbols(0,0,circles=1,inches=F,add=T)
}

Importancia de cada variable - varianza ponderada por el tamaño de la celda:

if (!empty_nodes) {
  sigma2 <- sqrt(apply(getCodes(model,1),2,function(x,effectif)
     {m<-sum(effectif*(x-weighted.mean(x,effectif))^2)/(sum(effectif)-1)},
     effectif=nb))
  print(sort(sigma2,decreasing=T))
}
fecha_cnt      tmax      tmin    precip 
0.9644986 0.9521914 0.9508620 0.9382128 

Clustering

if (!empty_nodes) {
  hac <- mpr.hac(model, nb)
}

VisualizaciĂ³n de 3 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=3)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=3)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax          tmin             precip          nevada 
 Min.   : 1.00   Min.   :-42   Min.   :-108.00   Min.   : 74.0   Min.   :0  
 1st Qu.: 2.00   1st Qu.:118   1st Qu.:  52.00   1st Qu.: 90.0   1st Qu.:0  
 Median : 8.00   Median :141   Median :  75.00   Median :101.0   Median :0  
 Mean   : 6.68   Mean   :143   Mean   :  74.86   Mean   :110.2   Mean   :0  
 3rd Qu.:11.00   3rd Qu.:169   3rd Qu.: 100.00   3rd Qu.:120.0   3rd Qu.:0  
 Max.   :12.00   Max.   :350   Max.   : 223.00   Max.   :422.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.93   1st Qu.: -8.419   1st Qu.:  33.0  
 Median :  0.000   Median :42.43   Median : -5.616   Median : 200.0  
 Mean   :  3.839   Mean   :41.29   Mean   : -5.252   Mean   : 372.8  
 3rd Qu.:  0.000   3rd Qu.:43.30   3rd Qu.: -2.039   3rd Qu.: 370.0  
 Max.   :892.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin             precip     
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   : 0.00  
 1st Qu.: 2.000   1st Qu.:119.0   1st Qu.:  25.00   1st Qu.: 6.00  
 Median : 4.000   Median :152.0   Median :  55.00   Median :16.00  
 Mean   : 5.781   Mean   :146.7   Mean   :  52.56   Mean   :20.98  
 3rd Qu.:11.000   3rd Qu.:177.0   3rd Qu.:  81.00   3rd Qu.:31.00  
 Max.   :12.000   Max.   :336.0   Max.   : 219.00   Max.   :98.00  
     nevada           prof_nieve           longitud        latitud        
 Min.   :0.000000   Min.   :   0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.000000   1st Qu.:   0.0000   1st Qu.:39.49   1st Qu.: -5.3456  
 Median :0.000000   Median :   0.0000   Median :41.19   Median : -2.7331  
 Mean   :0.000573   Mean   :   0.7996   Mean   :40.55   Mean   : -2.7938  
 3rd Qu.:0.000000   3rd Qu.:   0.0000   3rd Qu.:42.36   3rd Qu.:  0.4942  
 Max.   :6.000000   Max.   :1834.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  64.0  
 Median : 412.0  
 Mean   : 518.3  
 3rd Qu.: 750.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   : 87.0   Min.   : 42.0   Min.   : 0.000   Min.   :0  
 1st Qu.: 6.000   1st Qu.:227.0   1st Qu.:122.0   1st Qu.: 1.000   1st Qu.:0  
 Median : 7.000   Median :258.0   Median :150.0   Median : 5.000   Median :0  
 Mean   : 7.273   Mean   :260.4   Mean   :150.1   Mean   : 8.265   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:291.0   3rd Qu.:177.0   3rd Qu.:13.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :56.000   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.: 0.00000   1st Qu.:37.26   1st Qu.: -5.8792   1st Qu.:  32  
 Median : 0.00000   Median :39.99   Median : -3.6781   Median :  91  
 Mean   : 0.00271   Mean   :38.64   Mean   : -4.0808   Mean   : 311  
 3rd Qu.: 0.00000   3rd Qu.:41.65   3rd Qu.:  0.3664   3rd Qu.: 567  
 Max.   :35.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2519  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

VisualizaciĂ³n de 4 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=4)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=4)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax          tmin             precip          nevada 
 Min.   : 1.00   Min.   :-42   Min.   :-108.00   Min.   : 74.0   Min.   :0  
 1st Qu.: 2.00   1st Qu.:118   1st Qu.:  52.00   1st Qu.: 90.0   1st Qu.:0  
 Median : 8.00   Median :141   Median :  75.00   Median :101.0   Median :0  
 Mean   : 6.68   Mean   :143   Mean   :  74.86   Mean   :110.2   Mean   :0  
 3rd Qu.:11.00   3rd Qu.:169   3rd Qu.: 100.00   3rd Qu.:120.0   3rd Qu.:0  
 Max.   :12.00   Max.   :350   Max.   : 223.00   Max.   :422.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.93   1st Qu.: -8.419   1st Qu.:  33.0  
 Median :  0.000   Median :42.43   Median : -5.616   Median : 200.0  
 Mean   :  3.839   Mean   :41.29   Mean   : -5.252   Mean   : 372.8  
 3rd Qu.:  0.000   3rd Qu.:43.30   3rd Qu.: -2.039   3rd Qu.: 370.0  
 Max.   :892.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin             precip     
 Min.   : 3.00   Min.   :-24.0   Min.   :-110.00   Min.   : 0.00  
 1st Qu.:10.00   1st Qu.:116.0   1st Qu.:  29.00   1st Qu.: 8.00  
 Median :11.00   Median :149.0   Median :  59.00   Median :20.00  
 Mean   :11.04   Mean   :146.6   Mean   :  58.91   Mean   :24.68  
 3rd Qu.:12.00   3rd Qu.:178.0   3rd Qu.:  87.00   3rd Qu.:37.00  
 Max.   :12.00   Max.   :336.0   Max.   : 219.00   Max.   :98.00  
     nevada            prof_nieve          longitud        latitud        
 Min.   :0.0000000   Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.0000000   1st Qu.:  0.0000   1st Qu.:39.86   1st Qu.: -5.4981  
 Median :0.0000000   Median :  0.0000   Median :41.32   Median : -2.7331  
 Mean   :0.0005034   Mean   :  0.3153   Mean   :40.64   Mean   : -2.8028  
 3rd Qu.:0.0000000   3rd Qu.:  0.0000   3rd Qu.:42.39   3rd Qu.:  0.5706  
 Max.   :3.0000000   Max.   :382.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  69.0  
 Median : 412.0  
 Mean   : 542.4  
 3rd Qu.: 779.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin             precip     
 Min.   :1.000   Min.   :-53.0   Min.   :-121.00   Min.   : 0.00  
 1st Qu.:2.000   1st Qu.:121.0   1st Qu.:  23.00   1st Qu.: 6.00  
 Median :3.000   Median :153.0   Median :  53.00   Median :15.00  
 Mean   :2.743   Mean   :146.7   Mean   :  48.89   Mean   :18.85  
 3rd Qu.:4.000   3rd Qu.:177.0   3rd Qu.:  77.00   3rd Qu.:28.00  
 Max.   :7.000   Max.   :259.0   Max.   : 177.00   Max.   :93.00  
     nevada           prof_nieve          longitud        latitud        
 Min.   :0.000000   Min.   :   0.000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.000000   1st Qu.:   0.000   1st Qu.:39.49   1st Qu.: -5.3456  
 Median :0.000000   Median :   0.000   Median :41.15   Median : -2.7331  
 Mean   :0.000614   Mean   :   1.079   Mean   :40.50   Mean   : -2.7885  
 3rd Qu.:0.000000   3rd Qu.:   0.000   3rd Qu.:42.36   3rd Qu.:  0.4942  
 Max.   :6.000000   Max.   :1834.000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  64.0  
 Median : 405.0  
 Mean   : 504.4  
 3rd Qu.: 735.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   : 87.0   Min.   : 42.0   Min.   : 0.000   Min.   :0  
 1st Qu.: 6.000   1st Qu.:227.0   1st Qu.:122.0   1st Qu.: 1.000   1st Qu.:0  
 Median : 7.000   Median :258.0   Median :150.0   Median : 5.000   Median :0  
 Mean   : 7.273   Mean   :260.4   Mean   :150.1   Mean   : 8.265   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:291.0   3rd Qu.:177.0   3rd Qu.:13.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :56.000   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.: 0.00000   1st Qu.:37.26   1st Qu.: -5.8792   1st Qu.:  32  
 Median : 0.00000   Median :39.99   Median : -3.6781   Median :  91  
 Mean   : 0.00271   Mean   :38.64   Mean   : -4.0808   Mean   : 311  
 3rd Qu.: 0.00000   3rd Qu.:41.65   3rd Qu.:  0.3664   3rd Qu.: 567  
 Max.   :35.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2519  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

VisualizaciĂ³n de 5 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=5)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=5)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.00   Min.   :156.0   Min.   :0  
 1st Qu.: 2.000   1st Qu.:109.0   1st Qu.: 49.75   1st Qu.:167.0   1st Qu.:0  
 Median :10.000   Median :129.5   Median : 71.50   Median :184.5   Median :0  
 Mean   : 7.396   Mean   :137.4   Mean   : 74.03   Mean   :199.3   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:151.0   3rd Qu.: 92.00   3rd Qu.:218.2   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :28.31   Min.   :-16.499   Min.   :   4.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -8.624   1st Qu.:  91.1  
 Median :  0.000   Median :42.24   Median : -8.411   Median : 261.0  
 Mean   :  7.531   Mean   :40.89   Mean   : -6.431   Mean   : 529.8  
 3rd Qu.:  0.000   3rd Qu.:42.89   3rd Qu.: -3.658   3rd Qu.: 370.0  
 Max.   :607.000   Max.   :43.46   Max.   :  2.825   Max.   :2400.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin             precip          nevada 
 Min.   : 1.000   Min.   :-42.0   Min.   :-108.00   Min.   : 74.0   Min.   :0  
 1st Qu.: 2.000   1st Qu.:119.0   1st Qu.:  52.00   1st Qu.: 89.0   1st Qu.:0  
 Median : 6.000   Median :142.0   Median :  75.00   Median : 99.0   Median :0  
 Mean   : 6.625   Mean   :143.4   Mean   :  74.93   Mean   :103.4   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:170.0   3rd Qu.: 101.00   3rd Qu.:114.0   3rd Qu.:0  
 Max.   :12.000   Max.   :326.0   Max.   : 211.00   Max.   :155.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:41.09   1st Qu.: -8.411   1st Qu.:  32.0  
 Median :  0.000   Median :42.43   Median : -5.600   Median : 149.0  
 Mean   :  3.554   Mean   :41.32   Mean   : -5.161   Mean   : 360.7  
 3rd Qu.:  0.000   3rd Qu.:43.31   3rd Qu.: -2.039   3rd Qu.: 370.0  
 Max.   :892.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin             precip     
 Min.   : 3.00   Min.   :-24.0   Min.   :-110.00   Min.   : 0.00  
 1st Qu.:10.00   1st Qu.:116.0   1st Qu.:  29.00   1st Qu.: 8.00  
 Median :11.00   Median :149.0   Median :  59.00   Median :20.00  
 Mean   :11.04   Mean   :146.6   Mean   :  58.91   Mean   :24.68  
 3rd Qu.:12.00   3rd Qu.:178.0   3rd Qu.:  87.00   3rd Qu.:37.00  
 Max.   :12.00   Max.   :336.0   Max.   : 219.00   Max.   :98.00  
     nevada            prof_nieve          longitud        latitud        
 Min.   :0.0000000   Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.0000000   1st Qu.:  0.0000   1st Qu.:39.86   1st Qu.: -5.4981  
 Median :0.0000000   Median :  0.0000   Median :41.32   Median : -2.7331  
 Mean   :0.0005034   Mean   :  0.3153   Mean   :40.64   Mean   : -2.8028  
 3rd Qu.:0.0000000   3rd Qu.:  0.0000   3rd Qu.:42.39   3rd Qu.:  0.5706  
 Max.   :3.0000000   Max.   :382.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  69.0  
 Median : 412.0  
 Mean   : 542.4  
 3rd Qu.: 779.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin             precip     
 Min.   :1.000   Min.   :-53.0   Min.   :-121.00   Min.   : 0.00  
 1st Qu.:2.000   1st Qu.:121.0   1st Qu.:  23.00   1st Qu.: 6.00  
 Median :3.000   Median :153.0   Median :  53.00   Median :15.00  
 Mean   :2.743   Mean   :146.7   Mean   :  48.89   Mean   :18.85  
 3rd Qu.:4.000   3rd Qu.:177.0   3rd Qu.:  77.00   3rd Qu.:28.00  
 Max.   :7.000   Max.   :259.0   Max.   : 177.00   Max.   :93.00  
     nevada           prof_nieve          longitud        latitud        
 Min.   :0.000000   Min.   :   0.000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.000000   1st Qu.:   0.000   1st Qu.:39.49   1st Qu.: -5.3456  
 Median :0.000000   Median :   0.000   Median :41.15   Median : -2.7331  
 Mean   :0.000614   Mean   :   1.079   Mean   :40.50   Mean   : -2.7885  
 3rd Qu.:0.000000   3rd Qu.:   0.000   3rd Qu.:42.36   3rd Qu.:  0.4942  
 Max.   :6.000000   Max.   :1834.000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  64.0  
 Median : 405.0  
 Mean   : 504.4  
 3rd Qu.: 735.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   : 87.0   Min.   : 42.0   Min.   : 0.000   Min.   :0  
 1st Qu.: 6.000   1st Qu.:227.0   1st Qu.:122.0   1st Qu.: 1.000   1st Qu.:0  
 Median : 7.000   Median :258.0   Median :150.0   Median : 5.000   Median :0  
 Mean   : 7.273   Mean   :260.4   Mean   :150.1   Mean   : 8.265   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:291.0   3rd Qu.:177.0   3rd Qu.:13.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :56.000   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.: 0.00000   1st Qu.:37.26   1st Qu.: -5.8792   1st Qu.:  32  
 Median : 0.00000   Median :39.99   Median : -3.6781   Median :  91  
 Mean   : 0.00271   Mean   :38.64   Mean   : -4.0808   Mean   : 311  
 3rd Qu.: 0.00000   3rd Qu.:41.65   3rd Qu.:  0.3664   3rd Qu.: 567  
 Max.   :35.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2519  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

VisualizaciĂ³n de 6 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=6)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=6)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.00   Min.   :156.0   Min.   :0  
 1st Qu.: 2.000   1st Qu.:109.0   1st Qu.: 49.75   1st Qu.:167.0   1st Qu.:0  
 Median :10.000   Median :129.5   Median : 71.50   Median :184.5   Median :0  
 Mean   : 7.396   Mean   :137.4   Mean   : 74.03   Mean   :199.3   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:151.0   3rd Qu.: 92.00   3rd Qu.:218.2   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :28.31   Min.   :-16.499   Min.   :   4.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -8.624   1st Qu.:  91.1  
 Median :  0.000   Median :42.24   Median : -8.411   Median : 261.0  
 Mean   :  7.531   Mean   :40.89   Mean   : -6.431   Mean   : 529.8  
 3rd Qu.:  0.000   3rd Qu.:42.89   3rd Qu.: -3.658   3rd Qu.: 370.0  
 Max.   :607.000   Max.   :43.46   Max.   :  2.825   Max.   :2400.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin             precip          nevada 
 Min.   : 1.000   Min.   :-42.0   Min.   :-108.00   Min.   : 74.0   Min.   :0  
 1st Qu.: 2.000   1st Qu.:119.0   1st Qu.:  52.00   1st Qu.: 89.0   1st Qu.:0  
 Median : 6.000   Median :142.0   Median :  75.00   Median : 99.0   Median :0  
 Mean   : 6.625   Mean   :143.4   Mean   :  74.93   Mean   :103.4   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:170.0   3rd Qu.: 101.00   3rd Qu.:114.0   3rd Qu.:0  
 Max.   :12.000   Max.   :326.0   Max.   : 211.00   Max.   :155.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:41.09   1st Qu.: -8.411   1st Qu.:  32.0  
 Median :  0.000   Median :42.43   Median : -5.600   Median : 149.0  
 Mean   :  3.554   Mean   :41.32   Mean   : -5.161   Mean   : 360.7  
 3rd Qu.:  0.000   3rd Qu.:43.31   3rd Qu.: -2.039   3rd Qu.: 370.0  
 Max.   :892.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip     
 Min.   : 3.00   Min.   :-15.0   Min.   :-75.00   Min.   :15.00  
 1st Qu.:10.00   1st Qu.:127.0   1st Qu.: 51.00   1st Qu.:27.00  
 Median :11.00   Median :162.0   Median : 81.00   Median :37.00  
 Mean   :10.68   Mean   :159.2   Mean   : 79.54   Mean   :40.82  
 3rd Qu.:12.00   3rd Qu.:193.0   3rd Qu.:108.00   3rd Qu.:52.00  
 Max.   :12.00   Max.   :336.0   Max.   :219.00   Max.   :98.00  
     nevada            prof_nieve          longitud        latitud        
 Min.   :0.0000000   Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.0000000   1st Qu.:  0.0000   1st Qu.:40.07   1st Qu.: -5.7333  
 Median :0.0000000   Median :  0.0000   Median :41.81   Median : -3.7225  
 Mean   :0.0002219   Mean   :  0.4076   Mean   :40.90   Mean   : -3.2806  
 3rd Qu.:0.0000000   3rd Qu.:  0.0000   3rd Qu.:42.87   3rd Qu.:  0.4914  
 Max.   :2.0000000   Max.   :382.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  52.0  
 Median : 258.0  
 Mean   : 489.7  
 3rd Qu.: 667.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt         tmax            tmin             precip      
 Min.   : 7.0   Min.   :-24.0   Min.   :-110.00   Min.   : 0.000  
 1st Qu.:11.0   1st Qu.:105.0   1st Qu.:  14.00   1st Qu.: 3.000  
 Median :12.0   Median :139.0   Median :  41.00   Median : 7.000  
 Mean   :11.4   Mean   :133.7   Mean   :  37.93   Mean   : 8.267  
 3rd Qu.:12.0   3rd Qu.:165.0   3rd Qu.:  65.00   3rd Qu.:13.000  
 Max.   :12.0   Max.   :234.0   Max.   : 121.00   Max.   :41.000  
     nevada            prof_nieve          longitud        latitud       
 Min.   :0.0000000   Min.   :  0.0000   Min.   :28.31   Min.   :-16.499  
 1st Qu.:0.0000000   1st Qu.:  0.0000   1st Qu.:39.49   1st Qu.: -4.127  
 Median :0.0000000   Median :  0.0000   Median :40.96   Median : -1.885  
 Mean   :0.0007895   Mean   :  0.2215   Mean   :40.37   Mean   : -2.317  
 3rd Qu.:0.0000000   3rd Qu.:  0.0000   3rd Qu.:41.77   3rd Qu.:  0.595  
 Max.   :3.0000000   Max.   :338.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  91.1  
 Median : 566.0  
 Mean   : 595.9  
 3rd Qu.: 846.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin             precip     
 Min.   :1.000   Min.   :-53.0   Min.   :-121.00   Min.   : 0.00  
 1st Qu.:2.000   1st Qu.:121.0   1st Qu.:  23.00   1st Qu.: 6.00  
 Median :3.000   Median :153.0   Median :  53.00   Median :15.00  
 Mean   :2.743   Mean   :146.7   Mean   :  48.89   Mean   :18.85  
 3rd Qu.:4.000   3rd Qu.:177.0   3rd Qu.:  77.00   3rd Qu.:28.00  
 Max.   :7.000   Max.   :259.0   Max.   : 177.00   Max.   :93.00  
     nevada           prof_nieve          longitud        latitud        
 Min.   :0.000000   Min.   :   0.000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.000000   1st Qu.:   0.000   1st Qu.:39.49   1st Qu.: -5.3456  
 Median :0.000000   Median :   0.000   Median :41.15   Median : -2.7331  
 Mean   :0.000614   Mean   :   1.079   Mean   :40.50   Mean   : -2.7885  
 3rd Qu.:0.000000   3rd Qu.:   0.000   3rd Qu.:42.36   3rd Qu.:  0.4942  
 Max.   :6.000000   Max.   :1834.000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  64.0  
 Median : 405.0  
 Mean   : 504.4  
 3rd Qu.: 735.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   : 87.0   Min.   : 42.0   Min.   : 0.000   Min.   :0  
 1st Qu.: 6.000   1st Qu.:227.0   1st Qu.:122.0   1st Qu.: 1.000   1st Qu.:0  
 Median : 7.000   Median :258.0   Median :150.0   Median : 5.000   Median :0  
 Mean   : 7.273   Mean   :260.4   Mean   :150.1   Mean   : 8.265   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:291.0   3rd Qu.:177.0   3rd Qu.:13.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :56.000   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.: 0.00000   1st Qu.:37.26   1st Qu.: -5.8792   1st Qu.:  32  
 Median : 0.00000   Median :39.99   Median : -3.6781   Median :  91  
 Mean   : 0.00271   Mean   :38.64   Mean   : -4.0808   Mean   : 311  
 3rd Qu.: 0.00000   3rd Qu.:41.65   3rd Qu.:  0.3664   3rd Qu.: 567  
 Max.   :35.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2519  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

VisualizaciĂ³n de 8 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=8)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=8)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.00   Min.   :156.0   Min.   :0  
 1st Qu.: 2.000   1st Qu.:109.0   1st Qu.: 49.75   1st Qu.:167.0   1st Qu.:0  
 Median :10.000   Median :129.5   Median : 71.50   Median :184.5   Median :0  
 Mean   : 7.396   Mean   :137.4   Mean   : 74.03   Mean   :199.3   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:151.0   3rd Qu.: 92.00   3rd Qu.:218.2   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :28.31   Min.   :-16.499   Min.   :   4.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -8.624   1st Qu.:  91.1  
 Median :  0.000   Median :42.24   Median : -8.411   Median : 261.0  
 Mean   :  7.531   Mean   :40.89   Mean   : -6.431   Mean   : 529.8  
 3rd Qu.:  0.000   3rd Qu.:42.89   3rd Qu.: -3.658   3rd Qu.: 370.0  
 Max.   :607.000   Max.   :43.46   Max.   :  2.825   Max.   :2400.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt         tmax            tmin            precip          nevada 
 Min.   : 5.0   Min.   :  2.0   Min.   :-53.00   Min.   : 83.0   Min.   :0  
 1st Qu.:10.0   1st Qu.:133.0   1st Qu.: 71.00   1st Qu.: 94.0   1st Qu.:0  
 Median :11.0   Median :158.0   Median : 92.00   Median :104.0   Median :0  
 Mean   :10.7   Mean   :161.5   Mean   : 92.87   Mean   :108.3   Mean   :0  
 3rd Qu.:12.0   3rd Qu.:187.0   3rd Qu.:115.00   3rd Qu.:120.0   3rd Qu.:0  
 Max.   :12.0   Max.   :326.0   Max.   :211.00   Max.   :155.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   : 0.0000   Min.   :28.31   Min.   :-17.755   Min.   :   1.0  
 1st Qu.: 0.0000   1st Qu.:40.78   1st Qu.: -8.411   1st Qu.:  27.0  
 Median : 0.0000   Median :42.43   Median : -4.846   Median : 108.0  
 Mean   : 0.4317   Mean   :41.19   Mean   : -4.814   Mean   : 287.1  
 3rd Qu.: 0.0000   3rd Qu.:43.31   3rd Qu.: -1.787   3rd Qu.: 261.0  
 Max.   :79.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip     
 Min.   : 3.00   Min.   :-15.0   Min.   :-75.00   Min.   :15.00  
 1st Qu.:10.00   1st Qu.:127.0   1st Qu.: 51.00   1st Qu.:27.00  
 Median :11.00   Median :162.0   Median : 81.00   Median :37.00  
 Mean   :10.68   Mean   :159.2   Mean   : 79.54   Mean   :40.82  
 3rd Qu.:12.00   3rd Qu.:193.0   3rd Qu.:108.00   3rd Qu.:52.00  
 Max.   :12.00   Max.   :336.0   Max.   :219.00   Max.   :98.00  
     nevada            prof_nieve          longitud        latitud        
 Min.   :0.0000000   Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.0000000   1st Qu.:  0.0000   1st Qu.:40.07   1st Qu.: -5.7333  
 Median :0.0000000   Median :  0.0000   Median :41.81   Median : -3.7225  
 Mean   :0.0002219   Mean   :  0.4076   Mean   :40.90   Mean   : -3.2806  
 3rd Qu.:0.0000000   3rd Qu.:  0.0000   3rd Qu.:42.87   3rd Qu.:  0.4914  
 Max.   :2.0000000   Max.   :382.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  52.0  
 Median : 258.0  
 Mean   : 489.7  
 3rd Qu.: 667.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt         tmax            tmin             precip      
 Min.   : 7.0   Min.   :-24.0   Min.   :-110.00   Min.   : 0.000  
 1st Qu.:11.0   1st Qu.:105.0   1st Qu.:  14.00   1st Qu.: 3.000  
 Median :12.0   Median :139.0   Median :  41.00   Median : 7.000  
 Mean   :11.4   Mean   :133.7   Mean   :  37.93   Mean   : 8.267  
 3rd Qu.:12.0   3rd Qu.:165.0   3rd Qu.:  65.00   3rd Qu.:13.000  
 Max.   :12.0   Max.   :234.0   Max.   : 121.00   Max.   :41.000  
     nevada            prof_nieve          longitud        latitud       
 Min.   :0.0000000   Min.   :  0.0000   Min.   :28.31   Min.   :-16.499  
 1st Qu.:0.0000000   1st Qu.:  0.0000   1st Qu.:39.49   1st Qu.: -4.127  
 Median :0.0000000   Median :  0.0000   Median :40.96   Median : -1.885  
 Mean   :0.0007895   Mean   :  0.2215   Mean   :40.37   Mean   : -2.317  
 3rd Qu.:0.0000000   3rd Qu.:  0.0000   3rd Qu.:41.77   3rd Qu.:  0.595  
 Max.   :3.0000000   Max.   :338.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  91.1  
 Median : 566.0  
 Mean   : 595.9  
 3rd Qu.: 846.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin             precip         nevada 
 Min.   :1.000   Min.   :-53.0   Min.   :-121.00   Min.   :10.0   Min.   :0  
 1st Qu.:2.000   1st Qu.:125.0   1st Qu.:  40.00   1st Qu.:24.0   1st Qu.:0  
 Median :3.000   Median :152.0   Median :  65.00   Median :31.0   Median :0  
 Mean   :3.171   Mean   :147.6   Mean   :  61.11   Mean   :34.6   Mean   :0  
 3rd Qu.:4.000   3rd Qu.:178.0   3rd Qu.:  88.00   3rd Qu.:42.0   3rd Qu.:0  
 Max.   :7.000   Max.   :259.0   Max.   : 177.00   Max.   :93.0   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :   0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:   0.000   1st Qu.:40.38   1st Qu.: -5.6983   1st Qu.:  58.0  
 Median :   0.000   Median :41.98   Median : -3.6781   Median : 258.0  
 Mean   :   2.043   Mean   :41.04   Mean   : -3.2023   Mean   : 503.2  
 3rd Qu.:   0.000   3rd Qu.:42.89   3rd Qu.:  0.4914   3rd Qu.: 667.0  
 Max.   :1834.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :1.000   Min.   :-42.0   Min.   :-108.0   Min.   : 74.00   Min.   :0  
 1st Qu.:1.000   1st Qu.:108.5   1st Qu.:  38.0   1st Qu.: 84.00   1st Qu.:0  
 Median :2.000   Median :127.0   Median :  58.0   Median : 93.00   Median :0  
 Mean   :2.349   Mean   :124.5   Mean   :  56.1   Mean   : 98.18   Mean   :0  
 3rd Qu.:3.000   3rd Qu.:149.0   3rd Qu.:  77.5   3rd Qu.:107.00   3rd Qu.:0  
 Max.   :6.000   Max.   :239.0   Max.   : 170.0   Max.   :155.00   Max.   :0  
   prof_nieve        longitud        latitud           altitud      
 Min.   :  0.00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.00   1st Qu.:41.91   1st Qu.: -8.616   1st Qu.:  42.0  
 Median :  0.00   Median :42.44   Median : -6.056   Median : 261.0  
 Mean   :  6.83   Mean   :41.46   Mean   : -5.526   Mean   : 437.9  
 3rd Qu.:  0.00   3rd Qu.:43.12   3rd Qu.: -2.039   3rd Qu.: 370.0  
 Max.   :892.00   Max.   :43.57   Max.   :  3.166   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   : 87.0   Min.   : 42.0   Min.   : 0.000   Min.   :0  
 1st Qu.: 6.000   1st Qu.:227.0   1st Qu.:122.0   1st Qu.: 1.000   1st Qu.:0  
 Median : 7.000   Median :258.0   Median :150.0   Median : 5.000   Median :0  
 Mean   : 7.273   Mean   :260.4   Mean   :150.1   Mean   : 8.265   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:291.0   3rd Qu.:177.0   3rd Qu.:13.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :56.000   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.: 0.00000   1st Qu.:37.26   1st Qu.: -5.8792   1st Qu.:  32  
 Median : 0.00000   Median :39.99   Median : -3.6781   Median :  91  
 Mean   : 0.00271   Mean   :38.64   Mean   : -4.0808   Mean   : 311  
 3rd Qu.: 0.00000   3rd Qu.:41.65   3rd Qu.:  0.3664   3rd Qu.: 567  
 Max.   :35.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2519  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt         tmax            tmin             precip      
 Min.   :1.00   Min.   :-46.0   Min.   :-114.00   Min.   : 0.000  
 1st Qu.:1.00   1st Qu.:118.0   1st Qu.:  14.00   1st Qu.: 3.000  
 Median :2.00   Median :154.0   Median :  43.00   Median : 7.000  
 Mean   :2.45   Mean   :146.2   Mean   :  40.54   Mean   : 8.094  
 3rd Qu.:3.00   3rd Qu.:176.0   3rd Qu.:  69.00   3rd Qu.:13.000  
 Max.   :7.00   Max.   :254.0   Max.   : 122.00   Max.   :31.000  
     nevada           prof_nieve           longitud        latitud        
 Min.   :0.000000   Min.   :   0.0000   Min.   :28.31   Min.   :-17.7550  
 1st Qu.:0.000000   1st Qu.:   0.0000   1st Qu.:38.99   1st Qu.: -4.6800  
 Median :0.000000   Median :   0.0000   Median :40.84   Median : -2.3308  
 Mean   :0.001033   Mean   :   0.4216   Mean   :40.14   Mean   : -2.5061  
 3rd Qu.:0.000000   3rd Qu.:   0.0000   3rd Qu.:41.70   3rd Qu.:  0.4942  
 Max.   :6.000000   Max.   :1073.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  71.0  
 Median : 507.0  
 Mean   : 505.2  
 3rd Qu.: 775.0  
 Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

VisualizaciĂ³n de 10 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=10)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=10)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)
  df.cluster09 <- subset(df, cluster==9)
  df.cluster10 <- subset(df, cluster==10)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster09 <- select(df.cluster09, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster10 <- select(df.cluster10, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.00   Min.   :156.0   Min.   :0  
 1st Qu.: 2.000   1st Qu.:109.0   1st Qu.: 49.75   1st Qu.:167.0   1st Qu.:0  
 Median :10.000   Median :129.5   Median : 71.50   Median :184.5   Median :0  
 Mean   : 7.396   Mean   :137.4   Mean   : 74.03   Mean   :199.3   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:151.0   3rd Qu.: 92.00   3rd Qu.:218.2   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :28.31   Min.   :-16.499   Min.   :   4.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -8.624   1st Qu.:  91.1  
 Median :  0.000   Median :42.24   Median : -8.411   Median : 261.0  
 Mean   :  7.531   Mean   :40.89   Mean   : -6.431   Mean   : 529.8  
 3rd Qu.:  0.000   3rd Qu.:42.89   3rd Qu.: -3.658   3rd Qu.: 370.0  
 Max.   :607.000   Max.   :43.46   Max.   :  2.825   Max.   :2400.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt         tmax            tmin            precip          nevada 
 Min.   : 5.0   Min.   :  2.0   Min.   :-53.00   Min.   : 83.0   Min.   :0  
 1st Qu.:10.0   1st Qu.:133.0   1st Qu.: 71.00   1st Qu.: 94.0   1st Qu.:0  
 Median :11.0   Median :158.0   Median : 92.00   Median :104.0   Median :0  
 Mean   :10.7   Mean   :161.5   Mean   : 92.87   Mean   :108.3   Mean   :0  
 3rd Qu.:12.0   3rd Qu.:187.0   3rd Qu.:115.00   3rd Qu.:120.0   3rd Qu.:0  
 Max.   :12.0   Max.   :326.0   Max.   :211.00   Max.   :155.0   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   : 0.0000   Min.   :28.31   Min.   :-17.755   Min.   :   1.0  
 1st Qu.: 0.0000   1st Qu.:40.78   1st Qu.: -8.411   1st Qu.:  27.0  
 Median : 0.0000   Median :42.43   Median : -4.846   Median : 108.0  
 Mean   : 0.4317   Mean   :41.19   Mean   : -4.814   Mean   : 287.1  
 3rd Qu.: 0.0000   3rd Qu.:43.31   3rd Qu.: -1.787   3rd Qu.: 261.0  
 Max.   :79.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip     
 Min.   : 3.00   Min.   :-15.0   Min.   :-75.00   Min.   :15.00  
 1st Qu.:10.00   1st Qu.:127.0   1st Qu.: 51.00   1st Qu.:27.00  
 Median :11.00   Median :162.0   Median : 81.00   Median :37.00  
 Mean   :10.68   Mean   :159.2   Mean   : 79.54   Mean   :40.82  
 3rd Qu.:12.00   3rd Qu.:193.0   3rd Qu.:108.00   3rd Qu.:52.00  
 Max.   :12.00   Max.   :336.0   Max.   :219.00   Max.   :98.00  
     nevada            prof_nieve          longitud        latitud        
 Min.   :0.0000000   Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.0000000   1st Qu.:  0.0000   1st Qu.:40.07   1st Qu.: -5.7333  
 Median :0.0000000   Median :  0.0000   Median :41.81   Median : -3.7225  
 Mean   :0.0002219   Mean   :  0.4076   Mean   :40.90   Mean   : -3.2806  
 3rd Qu.:0.0000000   3rd Qu.:  0.0000   3rd Qu.:42.87   3rd Qu.:  0.4914  
 Max.   :2.0000000   Max.   :382.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  52.0  
 Median : 258.0  
 Mean   : 489.7  
 3rd Qu.: 667.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt         tmax            tmin             precip      
 Min.   : 7.0   Min.   :-24.0   Min.   :-110.00   Min.   : 0.000  
 1st Qu.:11.0   1st Qu.:105.0   1st Qu.:  14.00   1st Qu.: 3.000  
 Median :12.0   Median :139.0   Median :  41.00   Median : 7.000  
 Mean   :11.4   Mean   :133.7   Mean   :  37.93   Mean   : 8.267  
 3rd Qu.:12.0   3rd Qu.:165.0   3rd Qu.:  65.00   3rd Qu.:13.000  
 Max.   :12.0   Max.   :234.0   Max.   : 121.00   Max.   :41.000  
     nevada            prof_nieve          longitud        latitud       
 Min.   :0.0000000   Min.   :  0.0000   Min.   :28.31   Min.   :-16.499  
 1st Qu.:0.0000000   1st Qu.:  0.0000   1st Qu.:39.49   1st Qu.: -4.127  
 Median :0.0000000   Median :  0.0000   Median :40.96   Median : -1.885  
 Mean   :0.0007895   Mean   :  0.2215   Mean   :40.37   Mean   : -2.317  
 3rd Qu.:0.0000000   3rd Qu.:  0.0000   3rd Qu.:41.77   3rd Qu.:  0.595  
 Max.   :3.0000000   Max.   :338.0000   Max.   :43.57   Max.   :  4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  91.1  
 Median : 566.0  
 Mean   : 595.9  
 3rd Qu.: 846.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax             tmin             precip          nevada 
 Min.   :1.000   Min.   :-53.00   Min.   :-121.00   Min.   :10.00   Min.   :0  
 1st Qu.:1.000   1st Qu.: 13.25   1st Qu.: -48.00   1st Qu.:31.00   1st Qu.:0  
 Median :2.000   Median : 42.00   Median : -24.00   Median :40.00   Median :0  
 Mean   :2.434   Mean   : 39.76   Mean   : -27.81   Mean   :42.03   Mean   :0  
 3rd Qu.:3.000   3rd Qu.: 68.75   3rd Qu.:  -4.00   3rd Qu.:51.00   3rd Qu.:0  
 Max.   :6.000   Max.   :121.00   Max.   :  31.00   Max.   :93.00   Max.   :0  
   prof_nieve         longitud        latitud            altitud    
 Min.   :   0.00   Min.   :28.31   Min.   :-16.4992   Min.   :   4  
 1st Qu.:   0.00   1st Qu.:40.80   1st Qu.: -4.0103   1st Qu.:1082  
 Median :   0.00   Median :42.47   Median :  0.7789   Median :2143  
 Mean   :  24.03   Mean   :41.55   Mean   : -1.3462   Mean   :1806  
 3rd Qu.:   0.00   3rd Qu.:42.64   3rd Qu.:  1.2717   3rd Qu.:2316  
 Max.   :1834.00   Max.   :43.54   Max.   :  2.8253   Max.   :2535  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :1.000   Min.   :-42.0   Min.   :-108.0   Min.   : 74.00   Min.   :0  
 1st Qu.:1.000   1st Qu.:108.5   1st Qu.:  38.0   1st Qu.: 84.00   1st Qu.:0  
 Median :2.000   Median :127.0   Median :  58.0   Median : 93.00   Median :0  
 Mean   :2.349   Mean   :124.5   Mean   :  56.1   Mean   : 98.18   Mean   :0  
 3rd Qu.:3.000   3rd Qu.:149.0   3rd Qu.:  77.5   3rd Qu.:107.00   3rd Qu.:0  
 Max.   :6.000   Max.   :239.0   Max.   : 170.0   Max.   :155.00   Max.   :0  
   prof_nieve        longitud        latitud           altitud      
 Min.   :  0.00   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.00   1st Qu.:41.91   1st Qu.: -8.616   1st Qu.:  42.0  
 Median :  0.00   Median :42.44   Median : -6.056   Median : 261.0  
 Mean   :  6.83   Mean   :41.46   Mean   : -5.526   Mean   : 437.9  
 3rd Qu.:  0.00   3rd Qu.:43.12   3rd Qu.: -2.039   3rd Qu.: 370.0  
 Max.   :892.00   Max.   :43.57   Max.   :  3.166   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt          tmax          tmin            precip          nevada 
 Min.   :1.000   Min.   : 70   Min.   :-41.00   Min.   :15.00   Min.   :0  
 1st Qu.:2.000   1st Qu.:133   1st Qu.: 46.00   1st Qu.:24.00   1st Qu.:0  
 Median :3.000   Median :156   Median : 68.00   Median :30.00   Median :0  
 Mean   :3.236   Mean   :157   Mean   : 68.89   Mean   :33.95   Mean   :0  
 3rd Qu.:4.000   3rd Qu.:181   3rd Qu.: 90.00   3rd Qu.:40.00   3rd Qu.:0  
 Max.   :7.000   Max.   :259   Max.   :177.00   Max.   :81.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.07   1st Qu.: -5.8728   1st Qu.:  47.0  
 Median :  0.0000   Median :41.91   Median : -3.7881   Median : 240.0  
 Mean   :  0.1195   Mean   :40.99   Mean   : -3.3646   Mean   : 389.2  
 3rd Qu.:  0.0000   3rd Qu.:43.12   3rd Qu.:  0.3264   3rd Qu.: 609.0  
 Max.   :248.0000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 4.000   Min.   :158.0   Min.   : 42.0   Min.   : 0.000   Min.   :0  
 1st Qu.: 7.000   1st Qu.:240.0   1st Qu.:134.0   1st Qu.: 0.000   1st Qu.:0  
 Median : 8.000   Median :270.0   Median :159.0   Median : 4.000   Median :0  
 Mean   : 7.934   Mean   :269.9   Mean   :158.2   Mean   : 7.919   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:298.0   3rd Qu.:184.0   3rd Qu.:12.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :56.000   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:37.28   1st Qu.: -5.7333   1st Qu.:  32.0  
 Median : 0.00000   Median :39.99   Median : -3.5556   Median :  91.0  
 Mean   : 0.00278   Mean   :38.80   Mean   : -3.8100   Mean   : 306.6  
 3rd Qu.: 0.00000   3rd Qu.:41.65   3rd Qu.:  0.4731   3rd Qu.: 567.0  
 Max.   :35.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2451.0  
if (!empty_nodes) summary(df.cluster09)
   fecha_cnt         tmax            tmin             precip      
 Min.   :1.00   Min.   :-46.0   Min.   :-114.00   Min.   : 0.000  
 1st Qu.:1.00   1st Qu.:118.0   1st Qu.:  14.00   1st Qu.: 3.000  
 Median :2.00   Median :154.0   Median :  43.00   Median : 7.000  
 Mean   :2.45   Mean   :146.2   Mean   :  40.54   Mean   : 8.094  
 3rd Qu.:3.00   3rd Qu.:176.0   3rd Qu.:  69.00   3rd Qu.:13.000  
 Max.   :7.00   Max.   :254.0   Max.   : 122.00   Max.   :31.000  
     nevada           prof_nieve           longitud        latitud        
 Min.   :0.000000   Min.   :   0.0000   Min.   :28.31   Min.   :-17.7550  
 1st Qu.:0.000000   1st Qu.:   0.0000   1st Qu.:38.99   1st Qu.: -4.6800  
 Median :0.000000   Median :   0.0000   Median :40.84   Median : -2.3308  
 Mean   :0.001033   Mean   :   0.4216   Mean   :40.14   Mean   : -2.5061  
 3rd Qu.:0.000000   3rd Qu.:   0.0000   3rd Qu.:41.70   3rd Qu.:  0.4942  
 Max.   :6.000000   Max.   :1073.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  71.0  
 Median : 507.0  
 Mean   : 505.2  
 3rd Qu.: 775.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster10)
   fecha_cnt          tmax            tmin           precip           nevada 
 Min.   :1.000   Min.   : 87.0   Min.   : 50.0   Min.   : 0.000   Min.   :0  
 1st Qu.:4.000   1st Qu.:206.0   1st Qu.:101.0   1st Qu.: 4.000   1st Qu.:0  
 Median :5.000   Median :220.0   Median :116.0   Median : 9.000   Median :0  
 Mean   :4.537   Mean   :220.7   Mean   :116.8   Mean   : 9.698   Mean   :0  
 3rd Qu.:5.000   3rd Qu.:236.0   3rd Qu.:131.0   3rd Qu.:15.000   3rd Qu.:0  
 Max.   :7.000   Max.   :300.0   Max.   :185.0   Max.   :30.000   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   :0.000000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:0.000000   1st Qu.:36.65   1st Qu.: -6.909   1st Qu.:  32.0  
 Median :0.000000   Median :39.86   Median : -3.928   Median :  87.0  
 Mean   :0.002416   Mean   :38.01   Mean   : -5.203   Mean   : 329.1  
 3rd Qu.:0.000000   3rd Qu.:41.67   3rd Qu.: -1.033   3rd Qu.: 608.1  
 Max.   :9.000000   Max.   :43.57   Max.   :  4.216   Max.   :2519.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1], dim(df.cluster09)[1], dim(df.cluster10)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08", "cluster09", "cluster10"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.hist(df.cluster09)

if (!empty_nodes) mpr.hist(df.cluster10)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster09)

if (!empty_nodes) mpr.boxplot(df.cluster10)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
  df.cluster09.grouped <- mpr.group_by_geo(df.cluster09)
  df.cluster10.grouped <- mpr.group_by_geo(df.cluster10)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster09.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster10.grouped)

LS0tCnRpdGxlOiAiQW7DoWxpc2lzIGRlIG1vZGVsb3MgU09NIC0gRnJlY3VlbmNpYSBkYXRvcyBkZSBlbnRyYWRhOiBtZXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTW9kZWxvCgoqIElEOiAzMjkKKiBEZXNjcmlwY2nDs246IAoqIEZyZWN1ZW5jaWE6IG1lcwoqIFZhcmlhYmxlczogZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAKKiBEaW1lbnNpb25lcyBkZWwgbWFwYTogNSw1CiogSXRlcmFjaW9uZXM6IDEwMDAKKiBQYXLDoW1ldHJvcyBhZGljaW9uYWxlczogCgpgYGB7cn0Kc291cmNlKCIuLi8uLi9saWIvc29tLXV0aWxzLlIiKQpzb3VyY2UoIi4uLy4uL2xpYi9tYXBzLXV0aWxzLlIiKQpgYGAKCiMgQ2FyZ2EgZGVsIG1vZGVsbyBkZXNkZSBkaXNjbwoKYGBge3J9Cm1wci5zZXRfYmFzZV9wYXRoX2FuYWx5c2lzKCkKbW9kZWwgPC0gbXByLmxvYWRfbW9kZWwoInNvbS0zMjkucmRzLnh6IikKc3VtbWFyeShtb2RlbCkKYGBgCgpgYGB7cn0KcGxvdChtb2RlbCwgdHlwZT0iY2hhbmdlcyIpCmBgYAoKIyBDYXJnYSBkZWwgZGF0YXNldCBkZSBlbnRyYWRhCgpgYGB7cn0KZGYgPC0gbXByLmxvYWRfZGF0YSgiZGF0b3NfbWVzLmNzdi54eiIpCmBgYAoKYGBge3J9CmRmCmBgYAoKYGBge3J9CnN1bW1hcnkoZGYpCmBgYAoKIyBDYXJnYSBkZSBsb3MgbWFwYXMKCmBgYHtyfQp3b3JsZCA8LSBuZV9jb3VudHJpZXMoc2NhbGUgPSAibWVkaXVtIiwgcmV0dXJuY2xhc3MgPSAic2YiKQpzcGFpbiA8LSBzdWJzZXQod29ybGQsIGFkbWluID09ICJTcGFpbiIpCmBgYAoKIyBNYXBhIGRlIGRlbnNpZGFkCgpgYGB7cn0KcGxvdChtb2RlbCwgdHlwZT0iY291bnQiLCBzaGFwZSA9ICJzdHJhaWdodCIsIHBhbGV0dGUubmFtZSA9IG1wci5kZWdyYWRlLmJsZXUpCmBgYAoKTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjZWxkYToKCmBgYHtyfQpuYiA8LSB0YWJsZShtb2RlbCR1bml0LmNsYXNzaWYpCnByaW50KG5iKQpgYGAKQ29tcHJvYmFjacOzbiBkZSBub2RvcyB2YWPDrW9zOgoKYGBge3J9CmRpbV9tb2RlbCA8LSA1KjU7Cmxlbl9uYiA9IGxlbmd0aChuYik7CmVtcHR5X25vZGVzIDwtIGRpbV9tb2RlbCAhPSBsZW5fbmI7CmlmIChlbXB0eV9ub2RlcykgewogIHByaW50KHBhc3RlKCJbV2FybmluZ10gRXhpc3RlbiBub2RvcyB2YWPDrW9zOiAiLCBsZW5fbmIsICIvIiwgZGltX21vZGVsKSkKfQpgYGAKCiMgTWFwYSBkZSBkaXN0YW5jaWEgZW50cmUgdmVjaW5vcwoKYGBge3J9CnBsb3QobW9kZWwsIHR5cGU9ImRpc3QubmVpZ2hib3VycyIsIHNoYXBlID0gInN0cmFpZ2h0IikKYGBgCgojIEluZmx1ZW5jaWEgZGUgbGFzIHZhcmlhYmxlcwoKYGBge3J9Cm1vZGVsX2NvbG5hbWVzID0gYygiZmVjaGFfY250IiwgInRtYXgiLCAidG1pbiIsICJwcmVjaXAiKQptb2RlbF9uY29sID0gbGVuZ3RoKG1vZGVsX2NvbG5hbWVzKQpgYGAKCiMjIE1hcGEgZGUgdmFyaWFibGVzLgoKYGBge3J9CnBsb3QobW9kZWwsIHNoYXBlID0gInN0cmFpZ2h0IikKYGBgCgojIyBNYXBhIGRlIGNhbG9yIHBvciB2YXJpYWJsZQoKYGBge3J9CnBhcihtZnJvdz1jKDMsNCkpCmZvciAoaiBpbiAxOm1vZGVsX25jb2wpIHsKICBwbG90KG1vZGVsLCB0eXBlPSJwcm9wZXJ0eSIsIHByb3BlcnR5PWdldENvZGVzKG1vZGVsLDEpWyxqXSwKICAgIHBhbGV0dGUubmFtZT1tcHIuY29vbEJsdWVIb3RSZWQsCiAgICBtYWluPW1vZGVsX2NvbG5hbWVzW2pdLAogICAgY2V4PTAuNSwgc2hhcGUgPSAic3RyYWlnaHQiKQp9CmBgYAoKIyMgQ29ycmVsYWNpw7NuIHBhcmEgY2FkYSBjb2x1bW5hIGRlbCB2ZWN0b3IgZGUgbm9kb3MKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgY29yIDwtIGFwcGx5KGdldENvZGVzKG1vZGVsLDEpLCAyLCBtcHIud2VpZ2h0ZWQuY29ycmVsYXRpb24sIHc9bmIsIHNvbT1tb2RlbCkKICBwcmludChjb3IpCn0KYGBgCgpSZXByZXNlbnRhY2nDs24gZGUgY2FkYSB2YXJpYWJsZSBlbiB1biBtYXBhIGRlIGZhY3RvcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwYXIobWZyb3c9YygxLDEpKQogIHBsb3QoY29yWzEsXSwgY29yWzIsXSwgeGxpbT1jKC0xLDEpLCB5bGltPWMoLTEsMSksIHR5cGU9Im4iKQogIGxpbmVzKGMoLTEsMSksYygwLDApKQogIGxpbmVzKGMoMCwwKSxjKC0xLDEpKQogIHRleHQoY29yWzEsXSwgY29yWzIsXSwgbGFiZWxzPW1vZGVsX2NvbG5hbWVzLCBjZXg9MC43NSkKICBzeW1ib2xzKDAsMCxjaXJjbGVzPTEsaW5jaGVzPUYsYWRkPVQpCn0KYGBgCgpJbXBvcnRhbmNpYSBkZSBjYWRhIHZhcmlhYmxlIC0gdmFyaWFuemEgcG9uZGVyYWRhIHBvciBlbCB0YW1hw7FvIGRlIGxhIGNlbGRhOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBzaWdtYTIgPC0gc3FydChhcHBseShnZXRDb2Rlcyhtb2RlbCwxKSwyLGZ1bmN0aW9uKHgsZWZmZWN0aWYpCiAgICAge208LXN1bShlZmZlY3RpZiooeC13ZWlnaHRlZC5tZWFuKHgsZWZmZWN0aWYpKV4yKS8oc3VtKGVmZmVjdGlmKS0xKX0sCiAgICAgZWZmZWN0aWY9bmIpKQogIHByaW50KHNvcnQoc2lnbWEyLGRlY3JlYXNpbmc9VCkpCn0KYGBgCgojIENsdXN0ZXJpbmcKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgaGFjIDwtIG1wci5oYWMobW9kZWwsIG5iKQp9CmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgMyBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTMpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz0zKQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDQgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz00KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9NCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNSBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTUpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz01KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNiBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTYpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz02KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDYgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNikKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiLCAiY2x1c3RlcjA2IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDYpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA2KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDggY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz04KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9OCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQogIGRmLmNsdXN0ZXIwNyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTcpCiAgZGYuY2x1c3RlcjA4IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OCkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNiA8LSBzZWxlY3QoZGYuY2x1c3RlcjA2LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDcgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA4IDwtIHNlbGVjdChkZi5jbHVzdGVyMDgsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwOCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSwgZGltKGRmLmNsdXN0ZXIwNylbMV0sIGRpbShkZi5jbHVzdGVyMDgpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIsICJjbHVzdGVyMDYiLCAiY2x1c3RlcjA3IiwgImNsdXN0ZXIwOCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA4KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKICBkZi5jbHVzdGVyMDcuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNykKICBkZi5jbHVzdGVyMDguZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOC5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDEwIGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9MTApCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz0xMCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQogIGRmLmNsdXN0ZXIwNyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTcpCiAgZGYuY2x1c3RlcjA4IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OCkKICBkZi5jbHVzdGVyMDkgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT05KQogIGRmLmNsdXN0ZXIxMCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEwKQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA2IDwtIHNlbGVjdChkZi5jbHVzdGVyMDYsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNyA8LSBzZWxlY3QoZGYuY2x1c3RlcjA3LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDggPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA5IDwtIHNlbGVjdChkZi5jbHVzdGVyMDksIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIxMCA8LSBzZWxlY3QoZGYuY2x1c3RlcjEwLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIxMCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSwgZGltKGRmLmNsdXN0ZXIwNylbMV0sIGRpbShkZi5jbHVzdGVyMDgpWzFdLCBkaW0oZGYuY2x1c3RlcjA5KVsxXSwgZGltKGRmLmNsdXN0ZXIxMClbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiwgImNsdXN0ZXIwNiIsICJjbHVzdGVyMDciLCAiY2x1c3RlcjA4IiwgImNsdXN0ZXIwOSIsICJjbHVzdGVyMTAiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjEwKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjEwKQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKICBkZi5jbHVzdGVyMDcuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNykKICBkZi5jbHVzdGVyMDguZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOCkKICBkZi5jbHVzdGVyMDkuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOSkKICBkZi5jbHVzdGVyMTAuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIxMCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIxMC5ncm91cGVkKQpgYGAK